#pragma once 
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <iostream>

#include "ConnectInfo.hpp"
#include "tool.hpp"
#include "UserManage.hpp"

#define MAX_ROUND_COUNT 10
#define TCP_PROT_ 17878

class TcpConnect
{
    public:
        TcpConnect()
        {
            new_sock_=-1;
            server_ = NULL;
        }
        ~TcpConnect()
        {

        }
        void SetSockfd(int fd)
        {
            new_sock_ = fd;
        }

        void SetServer(void* server)
        {
            server_ = server;
        }

        int GetSockfd()
        {
            return new_sock_;
        }

        void* GetServer()
        {
            return server_;
        }
    private:
        int new_sock_;
        //保存ChatServer这个类的this指针，确保在tcp的线程入口函数当中可以获取到用户管理模块的实例化指针
        void* server_;
};

class ChatServer  
{
    public:
        //构造
        ChatServer() 
        {
           //tcp套接字
           tcp_sock_ = -1;
           user_manager_ = NULL;

        }
        //析构
        ~ChatServer()
        {
            
        }
        //初始化：负责创建tcp套接字，绑定，监听
        int InitSvr(uint16_t tcp_port = TCP_PROT_)
        {
            //创建tcp套接字
           tcp_sock_ = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
           if(tcp_sock_ < 0)
           {
               return -1;
           }
            
           //绑定
           struct sockaddr_in addr;
           addr.sin_family = AF_INET;
           addr.sin_port = htons(tcp_port);
           addr.sin_addr.s_addr = inet_addr("0.0.0.0");
           int ret = bind(tcp_sock_,(struct sockaddr*)&addr,sizeof(addr));
           if(ret < 0)
           {
                return -2;
           }

           ret = listen(tcp_sock_,5);
           if(ret < 0)
           {
               return -3;
           }
          
          // Log(INFO,__FILE__,__LINE__,"listen port is ")<<tcp_port << endl;
          LOG(INFO,"test") << endl;
          //创建用户管理模块的指针
          user_manager_ = new UserManager();
          if(user_manager_)
          {
              LOG(INFO,"user_manager_ failed") << endl;
              return -1;
          }
        }

        //启动线程
        int Start()
        {
            //tcp接收
            struct sockaddr_in peer_addr;
            socklen_t peer_addrlen = sizeof(peer_addr);
            while(1)
            {
                int new_sock = accept(tcp_sock_,(struct sockaddr*)&peer_addr,&peer_addrlen);
                if(new_sock < 0)
                {
                    continue;
                }
                //正常接收,创建线程开始处理
                TcpConnect* tc = new TcpConnect();
                tc->SetSockfd(new_sock);
                tc->SetServer((void*)this);

                pthread_t tid;
                int ret = pthread_create(&tid,NULL,LoginRegisterStart,(void*)tc);
                if(ret < 0)
                {
                    continue;
                }

            }
        }
        //处理登录注册的线程
        static void* LoginRegisterStart(void* arg)
        {
            /*1.注册
             *
             *
              2.登录*/
            pthread_detach(pthread_self());
            TcpConnect* tc = (TcpConnect*)arg;
            ChatServer* cs = (ChatServer*)tc->GetServer(); 
            char ques_type = -1;
            ssize_t recv_size = recv(tc->GetSockfd(),&ques_type,1,0);
            if(recv_size < 0)
            {
                close(tc->GetSockfd());
                return NULL;
            }
            else if(recv_size == 0)
            {
                //recv_size等于0，表示对端将连接关闭掉了，我们的策略也是关闭自己对该连接保存的套接字
                close(tc->GetSockfd());
                return NULL;
            }

            //接收回来了一个字节的数据
            int resp_status = -1 ;
            uint32_t user_id;
            switch(ques_type)
            {
                case REGISTER_RESQ:
                    {
                        //处理注册请求,DealRegister  
                        //TODO
                        resp_status =  cs->DealRegister(tc->GetSockfd(),&user_id);
                        break; 
                    }
                case LOGIN_RESQ:
                    {
                        //处理登录请求
                        resp_status = cs->DealLogin(tc->GetSockfd(),&user_id);
                        break;
                    }
            }
            //响应的构造
            //struct ReplyInfo
            //      status
            //      userid 
            //send进行发送
        
            struct ReplyInfo ri;
            ri.resp_status_ = resp_status;
            ri.id_ = user_id; 

            LOG(INFO,"resp_status is ") << ri.resp_status_ << endl;
            LOG(INFO,"id is ") << ri.id_ << endl;
            int max_round_count = MAX_ROUND_COUNT; 
            while(max_round_count > 0)
            {
                ssize_t send_size = send(tc->GetSockfd(),&ri,sizeof(ri),0);
                if(send_size >= 0)
                {
                    LOG(INFO,"Send reply success") << endl;
                    break;
                }
                    //发送失败之后，是否需要重复发送？（需要不需要将待发送的数据进行缓存起来）， 怎么发送
                LOG(WARNING,"Send reply failed") << endl;
                max_round_count--;
            }

            //关闭当前连接的套接字
            close(tc->GetSockfd());
            delete tc;
            tc = NULL;
            return NULL;
        } 

        //不管是注册成功了，还是失败了，都需要给客户端返回一个应答
        int DealRegister(int new_sock,uint32_t* user_id)
        {
            //继续从tcp连接当中接收注册数据，策略就是，直接使用RegisterInfo
            struct RegisterInfo ri;
            ssize_t recv_size = recv(new_sock,&ri,sizeof(ri),0);
            if(recv_size < 0)
            {
                return -1;
            }
            
            else if(recv_size == 0)
            {
                close(new_sock);
                return -2;
            }

            //正常接收到了
            //需要将数据递交给用户管理模块，进行注册，并且将用户数据进行留存
            //需要和用户管理模块进行交互了
            //TODO
           int ret =  user_manager_->DealRegister(ri.nick_name_,ri.school_,ri.passwd_,user_id); 
           if(ret < 0)
           {
                //注册失败了
                return REGISTER_FAILED;
           }

           //注册成功了
            return REGISTER_SUCCESS; 
        }

        int DealLogin(int new_sock,uint32_t* user_id)
        {
            //继续从tcp连接中接收登录数据，策略就是直接使用LoginInfo
            struct LoginInfo li;

            ssize_t recv_size = recv(new_sock,&li,sizeof(li),0);
            if(recv_size < 0)
            {
                return -1;
            }
            else if(recv_size == 0)
            {
                close(new_sock);
                return -2;
            }
            *user_id = li.id_;
            //正常的逻辑
            //TODO 调用用户管理模块，判断登录请求当中的id和密码是否正确
            int ret = user_manager_->DealLogin(li.id_,li.passwd_);
            if(ret < 0)
            {
                return LOGIN_FAILED;
            }
            return LOGIN_SUCCESS;
        }

    private:
        int tcp_sock_;//tcp套接字，负责处理登录注册
        int udp_sock_;//udp套接字，负责处理消息的收发
        
        UserManager* user_manager_;
};
